/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

package xowl.interpreter.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 *
 * @author Laurent WOUTERS
 */
public class Sequences {
    // <editor-fold defaultstate="collapsed" desc="Class Sequence Management">
    public static List<xowl.lang.runtime.Class> toEvaluatedList(Evaluator evaluator, xowl.lang.owl2.ClassSequenceExpression exp) throws xowl.interpreter.XOWLException {
        List<xowl.lang.runtime.Class> result = new ArrayList<xowl.lang.runtime.Class>();
        if (exp instanceof xowl.lang.actions.ToSeq) {
            xowl.lang.runtime.Array array = evaluator.evalArray(evaluator, ((xowl.lang.actions.ToSeq)exp).getArray());
            for (xowl.lang.runtime.Value value : xowl.utils.Values.toList(array))
                result.add(evaluator.toClass(value));
        } else {
            List<xowl.lang.owl2.ClassElement> elements = new ArrayList<xowl.lang.owl2.ClassElement>(((xowl.lang.owl2.ClassSequence)exp).getAllClassElements());
            sortElements(elements);
            for (xowl.lang.owl2.ClassElement elem : elements)
                result.add(evaluator.evalClass(evaluator, elem.getClasse()));
        }
        return result;
    }
    public static List<xowl.lang.owl2.ClassExpression> toExpressionList(xowl.lang.owl2.ClassSequenceExpression exp) {
        List<xowl.lang.owl2.ClassExpression> result = new ArrayList<xowl.lang.owl2.ClassExpression>();
        List<xowl.lang.owl2.ClassElement> elements = new ArrayList<xowl.lang.owl2.ClassElement>(((xowl.lang.owl2.ClassSequence)exp).getAllClassElements());
        sortElements(elements);
        for (xowl.lang.owl2.ClassElement elem : elements)
            result.add(elem.getClasse());
        return result;
    }
    public static xowl.lang.owl2.ClassSequence toSequence_Class(List<xowl.lang.owl2.ClassExpression> list) {
        xowl.lang.owl2.ClassSequence seq = new xowl.lang.owl2.ClassSequence();
        for (int i=0; i!=list.size(); i++) {
            xowl.lang.owl2.ClassElement elem = new xowl.lang.owl2.ClassElement();
            elem.setClasse(list.get(i));
            elem.setIndex(i);
            seq.addClassElements(elem);
        }
        return seq;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Datatype Sequence Management">
    public static List<xowl.lang.runtime.Datatype> toEvaluatedList(Evaluator evaluator, xowl.lang.owl2.DatarangeSequenceExpression exp) throws xowl.interpreter.XOWLException {
        List<xowl.lang.runtime.Datatype> result = new ArrayList<xowl.lang.runtime.Datatype>();
        if (exp instanceof xowl.lang.actions.ToSeq) {
            xowl.lang.runtime.Array array = evaluator.evalArray(evaluator, ((xowl.lang.actions.ToSeq)exp).getArray());
            for (xowl.lang.runtime.Value value : xowl.utils.Values.toList(array))
                result.add(evaluator.toDatatype(value));
        } else {
            List<xowl.lang.owl2.DatarangeElement> elements = new ArrayList<xowl.lang.owl2.DatarangeElement>(((xowl.lang.owl2.DatarangeSequence)exp).getAllDatarangeElements());
            sortElements(elements);
            for (xowl.lang.owl2.DatarangeElement elem : elements)
                result.add(evaluator.evalDatatype(evaluator, elem.getDatarange()));
        }
        return result;
    }
    public static List<xowl.lang.owl2.Datarange> toExpressionList(xowl.lang.owl2.DatarangeSequenceExpression exp) {
        List<xowl.lang.owl2.Datarange> result = new ArrayList<xowl.lang.owl2.Datarange>();
        List<xowl.lang.owl2.DatarangeElement> elements = new ArrayList<xowl.lang.owl2.DatarangeElement>(((xowl.lang.owl2.DatarangeSequence)exp).getAllDatarangeElements());
        sortElements(elements);
        for (xowl.lang.owl2.DatarangeElement elem : elements)
            result.add(elem.getDatarange());
        return result;
    }
    public static xowl.lang.owl2.DatarangeSequence toSequence_Datatype(List<xowl.lang.owl2.Datarange> list) {
        xowl.lang.owl2.DatarangeSequence seq = new xowl.lang.owl2.DatarangeSequence();
        for (int i=0; i!=list.size(); i++) {
            xowl.lang.owl2.DatarangeElement elem = new xowl.lang.owl2.DatarangeElement();
            elem.setDatarange(list.get(i));
            elem.setIndex(i);
            seq.addDatarangeElements(elem);
        }
        return seq;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Object Property Sequence Management">
    public static List<xowl.lang.runtime.ObjectProperty> toEvaluatedList(Evaluator evaluator, xowl.lang.owl2.ObjectPropertySequenceExpression exp) throws xowl.interpreter.XOWLException {
        List<xowl.lang.runtime.ObjectProperty> result = new ArrayList<xowl.lang.runtime.ObjectProperty>();
        if (exp instanceof xowl.lang.actions.ToSeq) {
            xowl.lang.runtime.Array array = evaluator.evalArray(evaluator, ((xowl.lang.actions.ToSeq)exp).getArray());
            for (xowl.lang.runtime.Value value : xowl.utils.Values.toList(array))
                result.add(evaluator.toObjProp(value));
        } else {
            List<xowl.lang.owl2.ObjectPropertyElement> elements = new ArrayList<xowl.lang.owl2.ObjectPropertyElement>(((xowl.lang.owl2.ObjectPropertySequence)exp).getAllObjectPropertyElements());
            sortElements(elements);
            for (xowl.lang.owl2.ObjectPropertyElement elem : elements)
                result.add(evaluator.evalObjProp(evaluator, elem.getObjectProperty()));
        }
        return result;
    }
    public static List<xowl.lang.owl2.ObjectPropertyExpression> toExpressionList(xowl.lang.owl2.ObjectPropertySequenceExpression exp) {
        List<xowl.lang.owl2.ObjectPropertyExpression> result = new ArrayList<xowl.lang.owl2.ObjectPropertyExpression>();
        List<xowl.lang.owl2.ObjectPropertyElement> elements = new ArrayList<xowl.lang.owl2.ObjectPropertyElement>(((xowl.lang.owl2.ObjectPropertySequence)exp).getAllObjectPropertyElements());
        sortElements(elements);
        for (xowl.lang.owl2.ObjectPropertyElement elem : elements)
            result.add(elem.getObjectProperty());
        return result;
    }
    public static xowl.lang.owl2.ObjectPropertySequence toSequence_ObjProp(List<xowl.lang.owl2.ObjectPropertyExpression> list) {
        xowl.lang.owl2.ObjectPropertySequence seq = new xowl.lang.owl2.ObjectPropertySequence();
        for (int i=0; i!=list.size(); i++) {
            xowl.lang.owl2.ObjectPropertyElement elem = new xowl.lang.owl2.ObjectPropertyElement();
            elem.setObjectProperty(list.get(i));
            elem.setIndex(i);
            seq.addObjectPropertyElements(elem);
        }
        return seq;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Data Property Sequence Management">
    public static List<xowl.lang.runtime.DataProperty> toEvaluatedList(Evaluator evaluator, xowl.lang.owl2.DataPropertySequenceExpression exp) throws xowl.interpreter.XOWLException {
        List<xowl.lang.runtime.DataProperty> result = new ArrayList<xowl.lang.runtime.DataProperty>();
        if (exp instanceof xowl.lang.actions.ToSeq) {
            xowl.lang.runtime.Array array = evaluator.evalArray(evaluator, ((xowl.lang.actions.ToSeq)exp).getArray());
            for (xowl.lang.runtime.Value value : xowl.utils.Values.toList(array))
                result.add(evaluator.toDataProp(value));
        } else {
            List<xowl.lang.owl2.DataPropertyElement> elements = new ArrayList<xowl.lang.owl2.DataPropertyElement>(((xowl.lang.owl2.DataPropertySequence)exp).getAllDataPropertyElements());
            sortElements(elements);
            for (xowl.lang.owl2.DataPropertyElement elem : elements)
                result.add(evaluator.evalDataProp(evaluator, elem.getDataProperty()));
        }
        return result;
    }
    public static List<xowl.lang.owl2.DataPropertyExpression> toExpressionList(xowl.lang.owl2.DataPropertySequenceExpression exp) {
        List<xowl.lang.owl2.DataPropertyExpression> result = new ArrayList<xowl.lang.owl2.DataPropertyExpression>();
        List<xowl.lang.owl2.DataPropertyElement> elements = new ArrayList<xowl.lang.owl2.DataPropertyElement>(((xowl.lang.owl2.DataPropertySequence)exp).getAllDataPropertyElements());
        sortElements(elements);
        for (xowl.lang.owl2.DataPropertyElement elem : elements)
            result.add(elem.getDataProperty());
        return result;
    }
    public static xowl.lang.owl2.DataPropertySequence toSequence_DataProp(List<xowl.lang.owl2.DataPropertyExpression> list) {
        xowl.lang.owl2.DataPropertySequence seq = new xowl.lang.owl2.DataPropertySequence();
        for (int i=0; i!=list.size(); i++) {
            xowl.lang.owl2.DataPropertyElement elem = new xowl.lang.owl2.DataPropertyElement();
            elem.setDataProperty(list.get(i));
            elem.setIndex(i);
            seq.addDataPropertyElements(elem);
        }
        return seq;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Individual Sequence Management">
    public static List<xowl.lang.runtime.Individual> toEvaluatedList(Evaluator evaluator, xowl.lang.owl2.IndividualSequenceExpression exp) throws xowl.interpreter.XOWLException {
        List<xowl.lang.runtime.Individual> result = new ArrayList<xowl.lang.runtime.Individual>();
        if (exp instanceof xowl.lang.actions.ToSeq) {
            xowl.lang.runtime.Array array = evaluator.evalArray(evaluator, ((xowl.lang.actions.ToSeq)exp).getArray());
            for (xowl.lang.runtime.Value value : xowl.utils.Values.toList(array))
                result.add(evaluator.toIndividual(value));
        } else {
            List<xowl.lang.owl2.IndividualElement> elements = new ArrayList<xowl.lang.owl2.IndividualElement>(((xowl.lang.owl2.IndividualSequence)exp).getAllIndividualElements());
            sortElements(elements);
            for (xowl.lang.owl2.IndividualElement elem : elements)
                result.add(evaluator.evalIndividual(evaluator, elem.getIndividual()));
        }
        return result;
    }
    public static List<xowl.lang.owl2.IndividualExpression> toExpressionList(xowl.lang.owl2.IndividualSequenceExpression exp) {
        List<xowl.lang.owl2.IndividualExpression> result = new ArrayList<xowl.lang.owl2.IndividualExpression>();
        List<xowl.lang.owl2.IndividualElement> elements = new ArrayList<xowl.lang.owl2.IndividualElement>(((xowl.lang.owl2.IndividualSequence)exp).getAllIndividualElements());
        sortElements(elements);
        for (xowl.lang.owl2.IndividualElement elem : elements)
            result.add(elem.getIndividual());
        return result;
    }
    public static xowl.lang.owl2.IndividualSequence toSequence_Ind(List<xowl.lang.owl2.IndividualExpression> list) {
        xowl.lang.owl2.IndividualSequence seq = new xowl.lang.owl2.IndividualSequence();
        for (int i=0; i!=list.size(); i++) {
            xowl.lang.owl2.IndividualElement elem = new xowl.lang.owl2.IndividualElement();
            elem.setIndividual(list.get(i));
            elem.setIndex(i);
            seq.addIndividualElements(elem);
        }
        return seq;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Literal Sequence Management">
    public static List<xowl.lang.runtime.Literal> toEvaluatedList(Evaluator evaluator, xowl.lang.owl2.LiteralSequenceExpression exp) throws xowl.interpreter.XOWLException {
        List<xowl.lang.runtime.Literal> result = new ArrayList<xowl.lang.runtime.Literal>();
        if (exp instanceof xowl.lang.actions.ToSeq) {
            xowl.lang.runtime.Array array = evaluator.evalArray(evaluator, ((xowl.lang.actions.ToSeq)exp).getArray());
            for (xowl.lang.runtime.Value value : xowl.utils.Values.toList(array))
                result.add(evaluator.toLiteral(value));
        } else {
            List<xowl.lang.owl2.LiteralElement> elements = new ArrayList<xowl.lang.owl2.LiteralElement>(((xowl.lang.owl2.LiteralSequence)exp).getAllLiteralElements());
            sortElements(elements);
            for (xowl.lang.owl2.LiteralElement elem : elements)
                result.add(evaluator.evalLiteral(evaluator, elem.getLiteral()));
        }
        return result;
    }
    public static List<xowl.lang.owl2.LiteralExpression> toExpressionList(xowl.lang.owl2.LiteralSequenceExpression exp) {
        List<xowl.lang.owl2.LiteralExpression> result = new ArrayList<xowl.lang.owl2.LiteralExpression>();
        List<xowl.lang.owl2.LiteralElement> elements = new ArrayList<xowl.lang.owl2.LiteralElement>(((xowl.lang.owl2.LiteralSequence)exp).getAllLiteralElements());
        sortElements(elements);
        for (xowl.lang.owl2.LiteralElement elem : elements)
            result.add(elem.getLiteral());
        return result;
    }
    public static xowl.lang.owl2.LiteralSequence toSequence_Lit(List<xowl.lang.owl2.LiteralExpression> list) {
        xowl.lang.owl2.LiteralSequence seq = new xowl.lang.owl2.LiteralSequence();
        for (int i=0; i!=list.size(); i++) {
            xowl.lang.owl2.LiteralElement elem = new xowl.lang.owl2.LiteralElement();
            elem.setLiteral(list.get(i));
            elem.setIndex(i);
            seq.addLiteralElements(elem);
        }
        return seq;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Expression Sequence Management">
    public static List<xowl.lang.runtime.Value> toEvaluatedList(Evaluator evaluator, xowl.lang.actions.ExpressionSequenceExpression exp) throws xowl.interpreter.XOWLException {
        List<xowl.lang.runtime.Value> result = new ArrayList<xowl.lang.runtime.Value>();
        if (exp instanceof xowl.lang.actions.ToSeq) {
            xowl.lang.runtime.Array array = evaluator.evalArray(evaluator, ((xowl.lang.actions.ToSeq)exp).getArray());
            for (xowl.lang.runtime.Value value : xowl.utils.Values.toList(array))
                result.add(value);
        } else {
            List<xowl.lang.actions.ExpressionElement> elements = new ArrayList<xowl.lang.actions.ExpressionElement>(((xowl.lang.actions.ExpressionSequence)exp).getAllExpressionElements());
            sortElements(elements);
            for (xowl.lang.actions.ExpressionElement elem : elements)
                result.add(evaluator.evaluate(evaluator, elem.getExpressionAs(null)));
        }
        return result;
    }
    public static xowl.lang.actions.ExpressionSequence toSequence_Exp(List<xowl.lang.owl2.Expression> list) {
        xowl.lang.actions.ExpressionSequence seq = new xowl.lang.actions.ExpressionSequence();
        for (int i=0; i!=list.size(); i++) {
            xowl.lang.actions.ExpressionElement elem = new xowl.lang.actions.ExpressionElement();
            elem.setExpression(list.get(i));
            elem.setIndex(i);
            seq.addExpressionElements(elem);
        }
        return seq;
    }
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="Query Variable Sequence Management">
    public static List<xowl.lang.actions.QueryVariable> toExpressionList(xowl.lang.actions.QueryVariableSequenceExpression exp) {
        List<xowl.lang.actions.QueryVariable> result = new ArrayList<xowl.lang.actions.QueryVariable>();
        List<xowl.lang.actions.QueryVariableElement> elements = new ArrayList<xowl.lang.actions.QueryVariableElement>(((xowl.lang.actions.QueryVariableSequence)exp).getAllVariableElements());
        sortElements(elements);
        for (xowl.lang.actions.QueryVariableElement elem : elements)
            result.add(elem.getQvariable());
        return result;
    }
    public static xowl.lang.actions.QueryVariableSequence toSequence_QVar(List<xowl.lang.actions.QueryVariable> list) {
        xowl.lang.actions.QueryVariableSequence seq = new xowl.lang.actions.QueryVariableSequence();
        for (int i=0; i!=list.size(); i++) {
            xowl.lang.actions.QueryVariableElement elem = new xowl.lang.actions.QueryVariableElement();
            elem.setQvariable(list.get(i));
            elem.setIndex(i);
            seq.addVariableElements(elem);
        }
        return seq;
    }
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="Array Management">
    
    public static List<xowl.lang.owl2.Expression> toList(xowl.lang.actions.Array_OR_Concat expression) {
        List<xowl.lang.owl2.Expression> results = new ArrayList<xowl.lang.owl2.Expression>();
        List<xowl.lang.actions.Element> elements = new ArrayList<xowl.lang.actions.Element>(expression.getAllElements());
        Collections.sort(elements, new Comparator<xowl.lang.actions.Element>() {
            @Override public int compare(xowl.lang.actions.Element left, xowl.lang.actions.Element right) {
                return left.getElemIndex().compareTo(right.getElemIndex());
            }
        });
        for (xowl.lang.actions.Element elem : elements)
            results.add(elem.getElemValue());
        return results;
    }
    // </editor-fold>

    private static void sortElements(List<? extends xowl.lang.owl2.SequenceElement> elements) {
        Collections.sort(elements, new Comparator<xowl.lang.owl2.SequenceElement>(){
            @Override public int compare(xowl.lang.owl2.SequenceElement left, xowl.lang.owl2.SequenceElement right) {
                return left.getIndex().compareTo(right.getIndex());
            }
        });
    }

    public static xowl.lang.owl2.Expression getFirst(xowl.lang.actions.Array array) {
        for (xowl.lang.actions.Element elem : array.getAllElements())
            if (elem.getElemIndex() == 0)
                return elem.getElemValue();
        return null;
    }
}
